<template>
	<!-- 海报(想让海报显示隐藏要用hidden，v-if关闭后没办法在完整的出来海报) 保存海报按钮和关闭按钮 在html代码中写出来 绑定点击方法然后透明 再用canvas 覆盖 -->
	<view class="canvas_box" :hidden="canvasFlag" @touchmove.stop="">
		<view @touchmove.stop="">
			<canvas class="canvas" canvas-id="myCanvas" />
		</view>
		<view class="canvas_box_mask" /><!-- 遮罩 -->
		<!-- 透明按钮，设置成canvas的点击事件 -->
		<view class="button-wrapper" :style="{top:`${btnStyle.top}`,left:`${btnStyle.left}`,width:`${btnStyle.width}`}" v-if="!canvasFlag">
			<cover-view class="button-item" @tap="saveCanvasImage" />
			<cover-view class="button-item" @tap="handleCancel" />
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				phoneH: 667,
				phoneW: 375,
				btnStyle: {
					top: 0,
					left: 0,
					width: 0,
				},
				ctx: null,
				options: {},
				hasCreated: false, //标记是否已经绘制完成
			}
		},
		props: {
			canvasFlag: {
				type: Boolean,
				default: true,
			},
			posterObj: {
				type: Object,
				default: () => ({})
			}
		},
		methods: {
			// 海报
			// 画圆角矩形 ctx、x起点、y起点、w宽度、h高度、r圆角半径、fillColor填充颜色、strokeColor边框颜色
			roundRect(ctx, x, y, w, h, r, fillColor, strokeColor, top = false, bottom = false) {
				// 开始绘制
				ctx.beginPath()
				// 绘制左上角圆弧 Math.PI = 180度
				// 圆心x起点、圆心y起点、半径、以3点钟方向顺时针旋转后确认的起始弧度、以3点钟方向顺时针旋转后确认的终止弧度
				if (top) {
					ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
					// 绘制border-top
					// 移动起点位置 x终点、y终点
					ctx.moveTo(x + r, y)
					// 画一条线 x终点、y终点
					ctx.lineTo(x + w - r, y)
					// 绘制右上角圆弧
					ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
					// 绘制border-right
					// 绘制右下角圆弧
					ctx.lineTo(x + w, y + h)
					ctx.lineTo(x, y + h)
					ctx.lineTo(x, y + r)
				}
				if (bottom) {
					ctx.moveTo(x, y)
					// 画一条线 x终点、y终点
					ctx.lineTo(x + w, y)

					ctx.lineTo(x + w, y + h - r)

					ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)

					ctx.lineTo(x + r, y + h)

					ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)

					// 绘制border-left
					ctx.lineTo(x, y)
				}
				if (fillColor) {
					// 因为边缘描边存在锯齿，最好指定使用 transparent 填充
					ctx.setFillStyle(fillColor)
					// 对绘画区域填充
					ctx.fill()
				}
				if (strokeColor) {
					// 因为边缘描边存在锯齿，最好指定使用 transparent 填充
					ctx.setStrokeStyle(strokeColor)
					// 画出当前路径的边框
					ctx.stroke()
				}
				// 关闭一个路径
				ctx.closePath()
				// 剪切，剪切之后的绘画绘制剪切区域内进行，需要save与restore 这个很重要 不然没办法保存
				ctx.clip()
			},

			/**
			 * canvas绘图相关，把文字转化成只能行数，多余显示省略号
			 * ctx: 当前的canvas
			 * text: 文本
			 * contentWidth: 文本最大宽度
			 * lineNumber: 显示几行
			 */
			createLine(ctx, start, end, color) {
				ctx.beginPath()
				ctx.moveTo(start[0], start[1])
				ctx.lineTo(end[0], end[1])
				ctx.strokeStyle = color
				ctx.closePath()
				ctx.stroke()
			},
			getImagePath(src) {
				return new Promise((resolve, reject) => {
					uni.getImageInfo({
						src,
						success: res => {
							resolve(res)
						},
						fail: err => {
							console.log(err)
							reject(err)
						}
					})
				})
			},
			//文字处理换行
			normliazeText(ctx, text, scaleW) {
				let temp = ""
				let isAdd = false
				for (let a = 0; a < text.length; a++) {
					if (ctx.measureText(temp).width < 200 * scaleW) {
						temp += text[a];
					} else {
						if (!isAdd) {
							isAdd = true
							temp += "..."
						}
					}
				}
				return temp
			},
			// 生成海报
			async createCanvasImage() {
				// if(this.hasCreated){
				// 	return
				// }
				this.$h.showLoading('海报生成中...')
				let phoneData = uni.getSystemInfoSync();
				this.phoneH = phoneData.windowHeight; //屏幕宽度
				this.phoneW = phoneData.windowWidth; //屏幕高度
				let scaleW = this.phoneW / 375; //按照苹果留 375*667比例 其他型号手机等比例缩放 显示
				let scaleH = this.phoneH / 667; //按照苹果留 375*667比例 其他型号手机等比例缩放 显示

				const ctx = uni.createCanvasContext('myCanvas', this);
				this.ctx = ctx
				let {
					url,
					code,
					avatar,
					userInfo,
					subTitle,
					title
				} = this.posterObj

				let startX = 30 * scaleW //开始横坐标
				let startY = 84 * scaleH //开始纵坐标
				let canvasW = this.phoneW - (30 * scaleW) * 2 //总宽度
				let canvasH = this.phoneH - (84 * scaleH) * 2 - 80 * scaleH //总高度

				//btn的style
				this.btnStyle.top = startY + canvasH + 'px'
				this.btnStyle.left = startX + 'px'
				this.btnStyle.width = canvasW + 'px'

				this.options = {
					x: startX,
					y: startY,
					width: canvasW,
					height: canvasH
				}

				ctx.draw() //清空原来的画图内容

				ctx.save();
				this.roundRect(ctx, startX, startY, canvasW, canvasH, 10, '#fff', '#fff', true); //绘制海报圆角背景白色的
				ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 可以继续绘制


				//绘制头像
				ctx.save();
				let r = 25 //半径
				// //覆盖绘制
				// //问题：在微信小程序使用canvas绘制圆角图片时，微信调试工具正常显示，android真机都不显示。
				// // 原因：因为ctx.clip()剪切区域使用的填充颜色是透明的，所以图片没出来。
				// // 解决方案：将剪切区域设置成实体颜色就好了。
				// // this.roundRect(ctx, 70, 100, 50, 50, 10,
				// // 	'#f7f7f7', '#f7f7f7') //绘制图片圆角背景
				// // ctx.drawImage(res.path, 70, 100, 50, 50, 10); //绘制图
				ctx.beginPath();
				ctx.arc(startX + 20 + r, startY + 20 + r, r, 0, Math.PI * 2);
				ctx.fill();
				ctx.clip(); //裁剪出一个圆形的画布，圆形以外的区域无法被绘制
				let avatarInfo = await this.getImagePath(avatar.replace(/http:/g, 'https:'))
				ctx.drawImage(avatarInfo.path, startX + 20, startY + 20, r * 2, r * 2, 10); //在圆形上填充图片，但坐标还是按一开始的画布坐标来
				ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 可以继续绘制



				//绘制发布者
				ctx.save()
				ctx.font = 'normal bold 14px sans-serif';
				ctx.setFontSize(14) //设置字体大小，默认10
				ctx.fillText(userInfo, startX + 2 * r + 40, startY + 40);
				ctx.restore()

				ctx.save()
				ctx.setFontSize(12) //设置字体大小，默认10
				ctx.setFillStyle('#cccccc') //文字颜色：默认黑色
				ctx.fillText(subTitle, startX + 2 * r + 40, startY + 60);
				ctx.restore()

				ctx.save()
				ctx.setFillStyle('#1c1c1c') //文字颜色：默认黑色
				ctx.setFontSize(14) //设置字体大小，默认10
				ctx.font = 'normal bold 14px sans-serif';
				ctx.fillText(this.normliazeText(ctx, title, scaleW), startX + 20, startY + 100)
				ctx.restore()

				//将网络图片转成本地路径 商品图片
				let minW = ~~(this.phoneW - (startX + 20) * 2)
				let minH = ~~(150 * scaleH)
				try {
					let info1 = await this.getImagePath(url)
					let infoWidth = ""
					let infoHeight = ""
					let {
						width,
						height
					} = info1
					if(width>height){
						infoHeight=height
						infoWidth=~~(infoHeight*minW/minH)
						ctx.drawImage(info1.path, 0, 0,infoWidth, infoHeight, startX + 20, startY + 120, minW, minH)
					}else{
						infoWidth=width
						infoHeight=~~(infoWidth*minH/minW)
						ctx.drawImage(info1.path, 0, 0,infoWidth, infoHeight, startX + 20, startY + 120, minW, minH)
					}
				} catch (err) {
					console.log(err)
				}
				// 绘制小程序码
				try {
					let info2 = await this.getImagePath(code)
					ctx.drawImage(info2.path, (this.phoneW - 70) - 100, ((startY + 130) + 160 * scaleH), 70 * scaleW, 70 * scaleW)
				} catch (err) {
					console.log(err)
				}
				// 小程序码end
				// 小程序的名称
				ctx.save()
				ctx.setFontSize(14)
				ctx.setFillStyle('#2f1709') //文字颜色：默认黑色
				ctx.font = 'normal bold 14px sans-serif';
				ctx.fillText('长按识别', (this.phoneW - 70) / 2 - 60, ((startY + 160) + 160 * scaleH));
				ctx.restore()
				// 小程序的名称end

				// 长按/扫描识别查看商品
				ctx.save()
				ctx.setFontSize(14)
				ctx.font = 'normal 14px sans-serif';
				ctx.fillText('查看内容', (this.phoneW - 70) / 2 - 60, ((startY + 180) + 160 * scaleH));
				ctx.restore()
				// 长按/扫描识别查看商品end

				//绘制保存按钮
				ctx.save();
				this.roundRect(ctx, startX, startY + canvasH, canvasW, 80 * scaleH, 18, '#fff', '#fff', false, true)
				ctx.restore();


				ctx.save()
				this.createLine(ctx, [startX, startY + canvasH], [startX + canvasW, startY + canvasH], '#eeeeee')
				ctx.setFontSize(14)
				ctx.setFillStyle('#343436') //文字颜色：默认黑色
				ctx.textAlign = 'center'
				ctx.textBaseline = 'middle'; //设置文本的垂直对齐方式
				ctx.fillText('保存图片到相册', this.phoneW / 2, startY + canvasH + 20 * scaleH);

				this.createLine(ctx, [startX, startY + canvasH + 40 * scaleH], [startX + canvasW, startY + canvasH + 40 * scaleH],
					'#eee')
				ctx.fillText('取消', this.phoneW / 2, startY + canvasH + 60 * scaleH);
				ctx.restore()
				// 绘制保存按钮 end

				ctx.draw()
				// this.hasCreated=true //绘制完成

				this.$emit("update:canvasFlag", false)
				this.$h.hideLoading()
			},

			// 保存到系统相册
			saveCanvasImage() {
				this.$h.showLoading('保存中')
				uni.getSetting({
					success: res => {
						// 获取设置成功
						if (!res.authSetting['scope.writePhotosAlbum']) {
							uni.openSetting({
								success: res => {
									uni.authorize({
										scope: 'scope.writePhotosAlbum',
										success: () => {
											this.saveImage()
										},
										fail: () => {
											this.$h.toast('授权失败')
										}
									})
								}
							});
						} else {
							this.saveImage()
						}
					}
				})
			},
			saveImage() {
				// 1-把画布转化成临时文件
				this.ctx.draw(false, uni.canvasToTempFilePath({
					canvasId: 'myCanvas',
					...this.options,
					quality: 1,
					success: res => {
						// 2-保存图片至相册
						uni.saveImageToPhotosAlbum({
							filePath: res.tempFilePath,
							success: res2 => {
								this.$h.toast('图片保存成功', true)
								this.handleCancel()
							},
							fail: err => {
								console.log(err)
								this.handleCancel()
								this.$h.toast('保存失败，稍后再试')
							},
							complete: () => {
								this.$h.hideLoading()
							}
						}, this)
					}
				}, this))
			},
			handleCancel() {
				this.$emit("update:canvasFlag", true)
			}
		}
	}
</script>

<style lang="scss">
	.content {
		text-align: center;
		height: 100%;
	}

	.canvas_box {
		.canvas_box_mask {
			width: 100%;
			height: 100%;
			position: fixed;
			top: 0;
			right: 0;
			bottom: 0;
			left: 0;
			background: rgba(0, 0, 0, 1);
			opacity: 0.3;
			z-index: 28;
		}

		.button-wrapper {
			position: fixed;
			z-index: 32;

			&>.button-item:not(:first-child) {
				border-bottom-left-radius: 45rpx;
				border-bottom-right-radius: 45rpx;
			}

			.button-item {
				width: 100%;
				height: 80rpx;
				line-height: 80rpx;
				font-size: 30rpx;
				color: #000;
				text-align: center;
			}
		}
	}

	.canvas {
		position: fixed !important;
		top: 0rpx;
		left: 0 !important;
		display: block !important;
		width: 100% !important;
		height: 90% !important;
		z-index: 30;
	}
</style>
